package com.nbsaas.boot.user.ext.resource;

import com.nbsaas.boot.rest.filter.Filter;
import com.nbsaas.boot.rest.request.LongId;
import com.nbsaas.boot.rest.response.ListResponse;
import com.nbsaas.boot.rest.response.ResponseObject;
import com.nbsaas.boot.user.api.apis.*;
import com.nbsaas.boot.user.api.domain.enums.AccountType;
import com.nbsaas.boot.user.api.domain.enums.SecurityType;
import com.nbsaas.boot.user.api.domain.field.UserAccountField;
import com.nbsaas.boot.user.api.domain.field.UserOauthConfigField;
import com.nbsaas.boot.user.api.domain.field.UserPasswordField;
import com.nbsaas.boot.user.api.domain.request.UserAccountRequest;
import com.nbsaas.boot.user.api.domain.request.UserInfoRequest;
import com.nbsaas.boot.user.api.domain.request.UserOauthTokenRequest;
import com.nbsaas.boot.user.api.domain.request.UserPasswordRequest;
import com.nbsaas.boot.user.api.domain.response.*;
import com.nbsaas.boot.user.data.entity.UserInfo;
import com.nbsaas.boot.user.ext.apis.PasswordApi;
import com.nbsaas.boot.user.ext.apis.UserExtApi;
import com.nbsaas.boot.user.ext.domain.request.*;
import com.nbsaas.boot.user.ext.domain.response.PasswordResponse;
import com.nbsaas.boot.user.ext.domain.response.TokenResponse;
import com.nbsaas.boot.user.ext.domain.response.UserInfoExtResponse;
import jakarta.annotation.Resource;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.Date;


@Service
public class UserExtResource implements UserExtApi {


    @Resource
    private UserAccountApi userAccountApi;

    @Resource
    private UserPasswordApi userPasswordApi;

    @Resource
    private UserInfoApi userInfoApi;

    @Resource
    private PasswordApi passwordApi;

    @Resource
    private UserOauthConfigApi userOauthConfigApi;

    @Resource
    private UserOauthTokenApi userOauthTokenApi;

    @Resource
    private UserRoleApi userRoleApi;

    @Transactional(readOnly = true)
    @Override
    public ResponseObject<Boolean> checkRegister(UserRegisterRequest request) {
        ResponseObject<Boolean> result = new ResponseObject<>();
        Long num = userAccountApi.countData(Filter.eq(UserAccountField.username, request.getUsername()),
                Filter.eq(UserAccountField.accountType, request.getAccountType()));
        if (num == null) {
            num = 0L;
        }
        if (num > 0) {
            result.setData(false);
        } else {
            result.setData(true);
        }
        return result;
    }

    @Transactional(readOnly = true)
    @Override
    public ResponseObject<Long> checkRegister2(UserRegisterRequest request) {
        ResponseObject<Long> result = new ResponseObject<Long>();
        Long num = userAccountApi.countData(Filter.eq(UserAccountField.username, request.getUsername()),
                Filter.eq(UserAccountField.accountType, request.getAccountType()));
        if (num == null) {
            num = 0L;
        }
        if (num > 0) {
            UserAccountResponse account = userAccountApi.oneData(Filter.eq(UserAccountField.username, request.getUsername()),
                    Filter.eq(UserAccountField.accountType, request.getAccountType()));
            result.setData(account.getUser());
        } else {
            result.setData(-1L);
        }
        return result;
    }


    @Transactional
    @Override
    public ResponseObject<UserInfoResponse> register(UserRegisterRequest request) {
        ResponseObject<UserInfoResponse> result = new ResponseObject<>();
        if (request.getAccountType() == null) {
            request.setAccountType(AccountType.account);
        }
        /**
         * 描述：查询user账户是否被备注
         */
        Long num = userAccountApi.countData(Filter.eq(UserAccountField.accountType, request.getAccountType()),
                Filter.eq(UserAccountField.username, request.getUsername()));
        if (num == null) {
            num = 0L;
        }
        if (num > 0) {
            result.setCode(503);
            result.setMsg("该用户名已被使用");
            return result;
        }
        /**
         * 描述：user表写入
         */
        UserInfoRequest userForm = new UserInfoRequest();
        userForm.setName(request.getUsername());
        userForm.setPhone(request.getUsername());
        userForm.setAccountNo(request.getUsername());
        userForm.setUserType(request.getUserType());
        UserInfoResponse response = userInfoApi.createData(userForm);

        /**
         * 描述：user账户表写入
         */
        UserAccountRequest userAccount = new UserAccountRequest();
        userAccount.setAccountType(request.getAccountType());
        userAccount.setUsername(request.getUsername());
        userAccount.setLoginSize(0);
        userAccount.setUser(response.getId());
        userAccountApi.createData(userAccount);

        PasswordRequest passwordRequest = new PasswordRequest();
        passwordRequest.setPassword(request.getPassword());
        PasswordResponse password = passwordApi.password(passwordRequest);

        UserPasswordRequest userPassword = new UserPasswordRequest();
        userPassword.setSalt(password.getSalt());
        userPassword.setPassword(password.getPassword());
        userPassword.setUser(response.getId());
        userPassword.setSecurityType(SecurityType.account);
        userPassword.setAddDate(new Date());
        userPassword.setLastDate(new Date());
        userPassword.setCheckSize(0);
        userPasswordApi.createData(userPassword);

        result.setData(response);
        return result;
    }

    @Transactional
    @Override
    public ResponseObject<?> updatePassword(UserUpdatePasswordRequest request) {
        ResponseObject<?> result = new ResponseObject<>();

        UserInfoResponse user = userInfoApi.oneData(Filter.eq("id", request.getId()));
        if (user == null) {
            result.setCode(501);
            result.setMsg("无效用户");
            return result;
        }
        UserPasswordResponse password = userPasswordApi.oneData(Filter.eq(UserPasswordField.user, request.getId()));
        if (password == null) {
            result.setCode(502);
            result.setMsg("没有设置密码");
            return result;
        }

        //检查老密码
        PasswordRequest req = new PasswordRequest();
        req.setSalt(password.getSalt());
        req.setPassword(request.getOldPassword());
        PasswordResponse ps = passwordApi.passwordBySalt(req);
        if (!ps.getPassword().equals(password.getPassword())) {
            result.setCode(503);
            result.setMsg("老密码不正确");
            return result;
        }

        PasswordRequest pasReq = new PasswordRequest();
        pasReq.setPassword(request.getPassword());
        PasswordResponse newPassword = passwordApi.password(pasReq);

        //修改密码
        UserPasswordRequest passwordDataRequest = new UserPasswordRequest();
        passwordDataRequest.setPassword(newPassword.getPassword());
        passwordDataRequest.setSalt(newPassword.getSalt());
        passwordDataRequest.setId(password.getId());
        userPasswordApi.update(passwordDataRequest);

        return result;
    }

    @Transactional
    @Override
    public ResponseObject<?> resetPassword(UserResetPasswordRequest request) {
        ResponseObject<?> result = new ResponseObject<>();

        UserInfoResponse user = userInfoApi.oneData(Filter.eq("id", request.getId()));
        if (user == null) {
            result.setCode(501);
            result.setMsg("无效用户");
            return result;
        }
        UserPasswordResponse password = userPasswordApi.oneData(Filter.eq(UserPasswordField.user, request.getId()));
        if (password == null) {
            UserPasswordRequest req = new UserPasswordRequest();
            req.setUser(request.getId());
            req.setSecurityType(SecurityType.account);
            password = userPasswordApi.createData(req);
        }

        PasswordRequest pasReq = new PasswordRequest();
        pasReq.setPassword(request.getPassword());
        PasswordResponse newPassword = passwordApi.password(pasReq);

        //修改密码
        UserPasswordRequest passwordDataRequest = new UserPasswordRequest();
        passwordDataRequest.setPassword(newPassword.getPassword());
        passwordDataRequest.setSalt(newPassword.getSalt());
        passwordDataRequest.setId(password.getId());
        userPasswordApi.update(passwordDataRequest);

        return result;
    }

    @Transactional
    @Override
    public ResponseObject<UserInfoExtResponse> login(UserLoginRequest request) {
        ResponseObject<UserInfoExtResponse> result = new ResponseObject<>();
        if (request.getAccountType() == null) {
            request.setAccountType(AccountType.phone);
        }
        UserAccountResponse account = userAccountApi.oneData(
                Filter.eq(UserAccountField.username, request.getUsername()),
                Filter.eq(UserAccountField.accountType, request.getAccountType())
        );
        if (account == null) {
            account = userAccountApi.oneData(
                    Filter.eq(UserAccountField.username, request.getUsername()),
                    Filter.eq(UserAccountField.accountType, AccountType.account));
        }
        if (account == null) {
            account = userAccountApi.oneData(
                    Filter.eq(UserAccountField.username, request.getUsername()),
                    Filter.eq(UserAccountField.accountType, AccountType.email));
        }
        if (account == null) {
            result.setCode(501);
            result.setMsg("账号不存在");
            return result;
        }
        UserInfo info = new UserInfo();
        info.setId(account.getUser());
        UserPasswordResponse password = userPasswordApi.oneData(Filter.eq("user.id", account.getUser()));
        if (password == null) {
            result.setCode(502);
            result.setMsg("密码不存在");
            return result;
        }
        PasswordRequest req = new PasswordRequest();
        req.setPassword(request.getPassword());
        req.setSalt(password.getSalt());
        PasswordResponse pwd = passwordApi.passwordBySalt(req);
        if (!pwd.getPassword().equals(password.getPassword())) {
            result.setCode(503);
            result.setMsg("密码错误");
            return result;
        }
        ResponseObject<UserInfoResponse> res = userInfoApi.view(new LongId(account.getUser()));
        if (res.getCode() != 200) {
            result.setCode(504);
            result.setMsg("没有用户信息");
            return result;
        }

        UserInfoExtResponse extResponse = new UserInfoExtResponse();
        BeanUtils.copyProperties(res.getData(), extResponse);

        result.setData(extResponse);
        return result;
    }

    @Transactional(isolation = Isolation.SERIALIZABLE)
    @Override
    public ResponseObject<UserInfoExtResponse> loginOauth(UserLoginOauthRequest request) {
        ResponseObject<UserInfoExtResponse> result = new ResponseObject<>();
        UserOauthConfigResponse config = userOauthConfigApi.oneData(Filter.eq(UserOauthConfigField.model, request.getType()));
        if (config == null) {
            result.setCode(501);
            result.setMsg("没有登录配置");
            return result;
        }
        OauthHandler oauthHandler = null;
        try {
            Class c = Class.forName(config.getClassName());
            oauthHandler = (OauthHandler) c.newInstance();
            oauthHandler.setKey(config.getAppKey());
            oauthHandler.setSecret(config.getAppSecret());
        } catch (Exception e) {
            result.setCode(502);
            result.setMsg("加载登录配置失败");
            return result;
        }
        String openId = "";
        TokenResponse response = oauthHandler.getToken(request.getCode());
        if (response != null) {
            openId = response.getOpenId();
        }
        if (!StringUtils.hasText(openId)) {
            result.setCode(503);
            result.setMsg("第三方授权失败");
            return result;
        }
        UserOauthTokenResponse token = userOauthTokenApi.oneData(Filter.eq("userOauthConfig.id", config.getId()),
                Filter.eq("openId", openId));
        if (token == null) {
            UserInfoRequest userInfoRequest = new UserInfoRequest();
            userInfoRequest.setUserType(1);
            UserInfoResponse res = userInfoApi.createData(userInfoRequest);

            UserOauthTokenRequest tokenDataRequest = new UserOauthTokenRequest();
            tokenDataRequest.setUser(res.getId());
            tokenDataRequest.setUserOauthConfig(config.getId());
            tokenDataRequest.setOpenId(openId);
            tokenDataRequest.setAccessToken(response.getAccessToken());
            tokenDataRequest.setRefreshToken(response.getRefreshToken());
            tokenDataRequest.setUnionId(response.getUnionid());
            userOauthTokenApi.createData(tokenDataRequest);

            UserInfoExtResponse ext = new UserInfoExtResponse();
            BeanUtils.copyProperties(res, ext);
            ext.setOpenId(openId);
            result.setData(ext);
            return result;
        } else {
            UserOauthTokenRequest req = new UserOauthTokenRequest();
            req.setId(token.getId());
            req.setAccessToken(response.getAccessToken());
            req.setRefreshToken(response.getRefreshToken());
            userOauthTokenApi.update(req);
        }

        UserInfoResponse user = userInfoApi.oneData(Filter.eq("id", token.getUser()));
        UserInfoExtResponse ext = new UserInfoExtResponse();
        BeanUtils.copyProperties(user, ext);
        ext.setOpenId(openId);
        ext.setSessionKey(response.getAccessToken());
        result.setData(ext);

        return result;
    }

    @Transactional
    @Override
    public ResponseObject<String> findOpenId(UserLoginOauthRequest request) {
        ResponseObject<String> result = new ResponseObject<>();
        ResponseObject<TokenResponse> res = findOpenData(request);
        if (res.getCode() != 200) {
            result.setCode(res.getCode());
            result.setMsg(res.getMsg());
            return result;
        }
        result.setData(res.getData().getOpenId());
        return result;
    }

    @Transactional
    @Override
    public ResponseObject<TokenResponse> findOpenData(UserLoginOauthRequest request) {
        ResponseObject<TokenResponse> result = new ResponseObject<>();
        UserOauthConfigResponse config = userOauthConfigApi.oneData(Filter.eq(UserOauthConfigField.model, request.getType()));
        if (config == null) {
            result.setCode(501);
            result.setMsg("没有登录配置");
            return result;
        }
        OauthHandler oauthHandler = null;
        try {
            Class c = Class.forName(config.getClassName());
            oauthHandler = (OauthHandler) c.newInstance();
            oauthHandler.setKey(config.getAppKey());
            oauthHandler.setSecret(config.getAppSecret());
        } catch (Exception e) {
            result.setCode(502);
            result.setMsg("加载登录配置失败");
            return result;
        }
        TokenResponse response = oauthHandler.getToken(request.getCode());
        result.setData(response);
        if (!StringUtils.hasText(response.getOpenId())) {
            result.setCode(503);
            result.setMsg("第三方授权失败");
            return result;
        }

        return result;
    }

    @Override
    public ListResponse<String> selectPermissionByUser(Long userId) {
        ListResponse<String> result = new ListResponse<>();
        userRoleApi.listData(Filter.eq("", userId));

        return null;
    }

    @Transactional
    @Override
    public ResponseObject<UserInfoExtResponse> loginByPhone(String phone) {
        ResponseObject<UserInfoExtResponse> result = new ResponseObject<>();
        if (!StringUtils.hasText(phone)) {
            result.setCode(501);
            result.setMsg("手机号码不能为空");
            return result;
        }
        UserAccountResponse account = userAccountApi.oneData(
                Filter.eq(UserAccountField.username, phone),
                Filter.eq(UserAccountField.accountType, AccountType.phone)
        );
        if (account == null) {
            UserInfoRequest userRequest = new UserInfoRequest();
            userRequest.setPhone(phone);
            userRequest.setName(phone);
            userRequest.setAddDate(new Date());
            userRequest.setLastDate(new Date());
            userRequest.setLoginSize(1);
            UserInfoResponse userRes = userInfoApi.createData(userRequest);

            UserAccountRequest req = new UserAccountRequest();
            req.setAccountType(AccountType.phone);
            req.setUsername(phone);
            req.setAddDate(new Date());
            req.setLastDate(new Date());
            req.setUser(userRes.getId());
            userAccountApi.createData(req);

            UserInfoExtResponse extResponse = new UserInfoExtResponse();
            BeanUtils.copyProperties(userRes, extResponse);

            result.setData(extResponse);
            return result;
        }
        ResponseObject<UserInfoResponse> res = userInfoApi.view(new LongId(account.getUser()));
        if (res.getCode() != 200) {
            result.setCode(504);
            result.setMsg("没有用户信息");
            return result;
        }

        Integer loginSize = res.getData().getLoginSize();
        if (loginSize == null) {
            loginSize = 0;
        }
        loginSize++;
        UserInfoRequest userRequest = new UserInfoRequest();
        userRequest.setLoginSize(loginSize);
        userRequest.setId(account.getUser());
        userInfoApi.updateData(userRequest);

        UserAccountRequest accountRequest = new UserAccountRequest();
        accountRequest.setId(account.getId());
        Integer accountLoginSize = account.getLoginSize();
        if (accountLoginSize == null) {
            accountLoginSize = 0;
        }
        accountLoginSize++;
        accountRequest.setLoginSize(accountLoginSize);
        accountRequest.setLastDate(new Date());
        userAccountApi.updateData(accountRequest);

        UserInfoExtResponse extResponse = new UserInfoExtResponse();
        BeanUtils.copyProperties(res.getData(), extResponse);

        result.setData(extResponse);
        return result;
    }
}
